#pragma once
#include "Thread.hpp"
#include "lock_guard.hpp"
#include <vector>
#include <queue>
#include <pthread.h>
#include <unistd.h>
using namespace ThreadCat;

/*const int gnum = 5;

template <class T>
class ThreadPool;

template <class T>
class ThreadData
{
public:
    ThreadData(ThreadPool<T> *tp, const std::string &n)
        : threadpool(tp), name(n)
    {
    }

public:
    ThreadPool<T> *threadpool;
    std::string name;
};

template <class T>
class ThreadPool
{
private:
    static void *handlerTask(void *args)
    {
        ThreadData<T> *td = static_cast<ThreadData<T> *>(args);
        while (true)
        {
            T t;
            {
                LockGuard lock(td->threadpool->mutex());
                //td->threadpool->lockQueue();
                while (td->threadpool->isQueueEmpty())
                {
                    td->threadpool->threadWait();
                }
                // pop本质，就是把任务从公共队列中拿到当前线程独立的栈中
                t = td->threadpool->pop();
                //td->threadpool->unlockQueue();
            }
            std::cout << td->name << "获取了一个" << t.toTaskString() << "并处理完成,结果是" << t() << std::endl;
        }
        delete td;
        return nullptr;
    }

public:
    void lockQueue() { pthread_mutex_lock(&mutex_); }
    void unlockQueue() { pthread_mutex_unlock(&mutex_); }
    bool isQueueEmpty() { return task_queue_.empty(); }
    void threadWait() { pthread_cond_wait(&cond_, &mutex_); }
    T pop()
    {
        T t = task_queue_.front();
        task_queue_.pop();
        return t;
    }
    pthread_mutex_t* mutex()
    {
        return &mutex_;
    }
public:
    ThreadPool(const int &num = gnum) : num_(num)
    {
        pthread_mutex_init(&mutex_, nullptr);
        pthread_cond_init(&cond_, nullptr);

        for (int i = 0; i < num_; ++i)
        {
            //创建多个线程并传递参数，由于在类内调用，需要用静态方法
            threads_.push_back(new Thread());
        }
    }

    void run()
    {
        for (const auto &t : threads_)
        {
            ThreadData<T> *td = new ThreadData<T>(this, t->threadname());
            t->start(handlerTask, td);
            std::cout << t->threadname() << std::endl;
        }
    }

    void push(const T &in)
    {
        LockGuard lock(&mutex_);
        //pthread_mutex_lock(&mutex_);
        task_queue_.push(in);
        pthread_cond_signal(&cond_);
        //pthread_mutex_unlock(&mutex_);
    }

    ~ThreadPool()
    {
        pthread_mutex_destroy(&mutex_);
        pthread_cond_destroy(&cond_);

        for (const auto &t : threads_)
        {
            delete t;
        }
    }

private:
    int num_;
    std::vector<Thread *> threads_;
    std::queue<T> task_queue_;
    pthread_mutex_t mutex_;
    pthread_cond_t cond_;
};*/

#include <mutex>
const int gnum = 5;

template <class T>
class ThreadPool;

template <class T>
class ThreadData
{
public:
    ThreadData(ThreadPool<T> *tp, const std::string &n)
        : threadpool(tp), name(n)
    {
    }

public:
    ThreadPool<T> *threadpool;
    std::string name;
};

template <class T>
class ThreadPool
{
private:
    ThreadPool(const int &num = gnum) : num_(num)
    {
        pthread_mutex_init(&mutex_, nullptr);
        pthread_cond_init(&cond_, nullptr);

        for (int i = 0; i < num_; ++i)
        {
            // 创建多个线程并传递参数，由于在类内调用，需要用静态方法
            threads_.push_back(new Thread());
        }
    }

    ThreadPool &operator=(const ThreadPool &) = delete;
    ThreadPool(const ThreadPool &) = delete;

    static void *handlerTask(void *args)
    {
        ThreadData<T> *td = static_cast<ThreadData<T> *>(args);
        while (true)
        {
            T t;
            {
                LockGuard lock(td->threadpool->mutex());
                // td->threadpool->lockQueue();
                while (td->threadpool->isQueueEmpty())
                {
                    td->threadpool->threadWait();
                }
                // pop本质，就是把任务从公共队列中拿到当前线程独立的栈中
                t = td->threadpool->pop();
                // td->threadpool->unlockQueue();
            }
            std::cout << td->name << "获取了一个" << t.toTaskString() << "并处理完成,结果是" << t() << std::endl;
        }
        delete td;
        return nullptr;
    }

public:
    void lockQueue() { pthread_mutex_lock(&mutex_); }
    void unlockQueue() { pthread_mutex_unlock(&mutex_); }
    bool isQueueEmpty() { return task_queue_.empty(); }
    void threadWait() { pthread_cond_wait(&cond_, &mutex_); }
    T pop()
    {
        T t = task_queue_.front();
        task_queue_.pop();
        return t;
    }
    pthread_mutex_t *mutex()
    {
        return &mutex_;
    }

public:
    void run()
    {
        for (const auto &t : threads_)
        {
            ThreadData<T> *td = new ThreadData<T>(this, t->threadname());
            t->start(handlerTask, td);
            std::cout << t->threadname() << std::endl;
        }
    }

    void push(const T &in)
    {
        LockGuard lock(&mutex_);
        // pthread_mutex_lock(&mutex_);
        task_queue_.push(in);
        pthread_cond_signal(&cond_);
        // pthread_mutex_unlock(&mutex_);
    }

    ~ThreadPool()
    {
        pthread_mutex_destroy(&mutex_);
        pthread_cond_destroy(&cond_);

        for (const auto &t : threads_)
        {
            delete t;
        }
    }

    static ThreadPool<T> *GetInstance()
    {
        if (tp == nullptr)
        {
            //std::lock_guard<mutex> lock(siglock);
            siglock.lock();
            if (nullptr == tp)
            {
                tp = new ThreadPool<T>();
            }
            siglock.unlock();
        }
        return tp;
    }

private:
    int num_;
    std::vector<Thread *> threads_;
    std::queue<T> task_queue_;
    pthread_mutex_t mutex_;
    pthread_cond_t cond_;

    
    static ThreadPool<T> *tp;
    static std::mutex siglock;
};

template <class T>
ThreadPool<T> *ThreadPool<T>::tp = nullptr;

template <class T>
std::mutex  ThreadPool<T>::siglock;